/*
 * For legal stuff see the file COPYRIGHT
 */
#import "ClientInfo.h"
#import "ClientInspector.h"
#import "SessionEditor.h"
#import "ExpenseEditor.h"
#import "Controller.h"

@interface ClientInspector(PRIVATE)
- enableAdd:(BOOL)addFlag delete:(BOOL)delFlag modify:(BOOL)modFlag;
- (void)enableAdd:(BOOL)flag;
- (void)enableModify:(BOOL)flag;
- (void)enableDelete:(BOOL)flag;
- (void)enableUndelete:(BOOL)flag;
- showView:newView mgr:(ViewMgr *)mgr;
- (void)updateButtons;
@end

@implementation ClientInspector

/*
 * Allow only one ClientInspector object to be created.
 */
+ sharedInstance
{
  static id obj;

  if ( ! obj ) {
    obj = [[ClientInspector alloc] init];
    [NXApp loadNibSection:"ClientInspector.nib" owner:obj withNames:NO];
  }

  return obj;
}

+ (void)updateButtons
{
  [[self sharedInstance] updateButtons];
}

- awakeFromNib
{
  NXRect frameRect;

  if (![popUpList isKindOf:[PopUpList class]])
    popUpList = [popUpButton target];

  [currentView getFrame:&frameRect];

  [[sessionView removeFromSuperview] setFrame:&frameRect];
  [[expenseView removeFromSuperview] setFrame:&frameRect];
  [[clientView  removeFromSuperview] setFrame:&frameRect];

  [[panel contentView] replaceSubview:currentView with:sessionView];
  currentView = sessionView;

  [viewsPanel free];
  [panel setFrameAutosaveName:"ClientInspector"];
  [self windowDidResize:panel];	/* make swap views adjust to saved size */

  [browser setDoubleAction:@selector(browserDoubleClick:)];
  controller = [NXApp delegate];

  [self decacheBrowser];	/* requires 'controller' to be set first... */
  [[browser matrixInColumn:0] selectCellAt:0 :0];
  return self;
}

- (void)decacheBrowser
{
  ClientInfo *info = [self selectedClient];	/* remember the selection */
  [[controller clientList] sort]; 		/* in case the name was modified */
  [browser loadColumnZero];			/* redisplay */
  [self selectClient:info]; 			/* reinstate the selection */
}

/*
 * Redraw the current view, but don't expose the window
 */
- (void)decacheView
{
  List *clientList = [controller clientList];

  /*
   * If there are no clients, force the display the Client View,
   * since it's the only meaningful one.
   */
  if ( [clientList count] == 0 )
    [self showClient:nil];

  [currentMgr mgrShow:self];
  [self updateButtons];
}

/*
 * Called by Controller
 */
- display
{
  [self decacheView];
  [panel makeKeyAndOrderFront:nil]; /* was just "orderFront:" */
  return self;
}

- (void)selectClientAt:(int)row
{
  Matrix *matrix = [browser matrixInColumn:0];
  [matrix selectCellAt:row :0]; 
}

- selectClient:(ClientInfo *)info
{
  id matrix = [browser matrixInColumn:0];
  List *clientList = [controller clientList];
  int i = [clientList indexOf:info];

  [matrix selectCellAt:i :0];
  return self;
}

- addClient:(ClientInfo *)info
{
  List *clientList = [controller clientList];
  
  [clientList addObjectIfAbsent:info];
  [self decacheBrowser];
  [controller decacheBrowser];
  [self selectClient:info];
  return self;
}

/*
 * Generic delete button - invoke the delete method of the
 * currently selected view. If the return value is non-nil,
 * we save the modified data structure to disk.
 */
- delete:sender
{
  if ( [currentMgr mgrDelete:self] ) {
    [controller saveClientInfo];
    [self updateButtons];
  }

  return self;
}

- undelete:sender
{
  if ( [currentMgr mgrUndelete:self] ) {
    [controller saveClientInfo];
    [self updateButtons];
  }    

  return self;
}

- add:sender
{
  if ( [currentMgr mgrAdd:self] ) {
    [controller saveClientInfo];
    [self updateButtons];
  }
  return self;
}

- modify:sender
{
  if ( [currentMgr mgrModify:self] ) {
    [controller saveClientInfo];
    [self updateButtons];
  }
  return self;
}

- (void)performAdd
{
  [addButton performClick:self];
}

- (void)performModify
{
  [modifyButton performClick:self];
}

/*
 * Called when the client is selected in the inspector's top browser
 */
- browserClick:sender
{
  [currentMgr mgrShow:self];
  [self updateButtons];
  return self;
}

- browserDoubleClick:sender
{
  if ( [currentMgr mgrDoubleClick:self] ) {
    [controller saveClientInfo];
    [self updateButtons];
  }

  return self;
}

/*
 * Called by the Client mgr when the delete button is pressed.
 */
- (ClientInfo *)deleteSelectedClient
{
  List *clientList = [controller clientList];
  ClientInfo *info = [clientList removeObject:[self selectedClient]];
  [self decacheBrowser];
  [controller decacheBrowser];
  return info;
}

- (ClientInfo *)selectedClient
{
  id matrix = [browser matrixInColumn:0];
  List *clientList = [controller clientList];
  return [clientList objectAt:[matrix selectedRow]];
}

/*
 * Called when a new session has been added via the main control panel.
 * This allows the browser to update if necessary.
 */
- updatedInfo:info
{
  if ( info == [self selectedClient] )
    [currentMgr mgrShow:self];	/* force redisplay */

  return self;
}

/*
 * Delegated methods of NXBrowser
 */
- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
  List *clientList = [controller clientList];
  int i, count = [clientList count];
  const char *name;
  id cell;
  
  for ( i = 0; i < count; i++ ) {
    [matrix addRow];
    name = [[clientList objectAt:i] clientName];
    cell = [matrix cellAt:i :0];	/* 1 dimen. matrix: always use col 0! */
    [cell setStringValue:name];
    [cell setLoaded:YES];
    [cell setLeaf:YES];
  }

  return count ;
}

- (void)closeMonth
{
  [sessionMgr forgetDeletions];
  [expenseMgr forgetDeletions];
  [clientMgr  forgetDeletions];
}

/*
 * Force button title to the right state. This is necessary
 * because PopupLists are a kludge.
 */
- (void)chooseCell:cell
{
  [popUpButton setTitle:[cell title]];
  [[popUpList itemList] selectCell:cell];
}

- showClient:sender
{
  [self chooseCell:clientMenuCell];
  [self showView:clientView mgr:clientMgr];
  return self;
}

- showHours:sender
{
  [self chooseCell:sessionMenuCell];
  [self showView:sessionView mgr:sessionMgr];
  return self;
}

- showExpenses:sender
{
  [self chooseCell:expenseMenuCell];
  [self showView:expenseView mgr:expenseMgr];
  return self;
}

- setDocEdited:(BOOL)flag
{
  [panel setDocEdited:flag];
  return self;
}

/*
 * Delegated methods of Window
 */
- windowDidResize:sender
{
  NXRect frameRect;

  [currentView getFrame:&frameRect];

  /* Tell the other swap views their new size */
  [sessionView setFrame:&frameRect];
  [expenseView setFrame:&frameRect];
  [clientView  setFrame:&frameRect];
  return self;
}

@end


@implementation ClientInspector(PRIVATE)

- enableAdd:(BOOL)addFlag delete:(BOOL)delFlag modify:(BOOL)modFlag
{
  [controller enableAdd:addFlag];
  [controller enableModify:modFlag];

  [self enableAdd:addFlag];
  [self enableModify:modFlag];
  [self enableDelete:delFlag];

  [self enableUndelete:[currentMgr canUndelete]];
  return self;
}

- showView:newView mgr:(ViewMgr *)mgr
{
  [panel disableFlushWindow];

  if (newView != currentView) {

    /* Bail out if the user want to save their edits */
    if ( [currentMgr isEditing] == NO ||
	NXRunAlertPanel( [NXApp appName],
			"Modified data has not been saved",
			"Let me save it!",
			"I don't give a hoot", NULL ) != NX_ALERTDEFAULT ) {

      [[panel contentView] replaceSubview:currentView with:newView];

      currentView = newView;
      currentMgr  = mgr;

      [mgr mgrShow:self];
      [self setDocEdited:[mgr isEditing]];
      [panel display];
      [self updateButtons];
    }
  }

  [[panel reenableFlushWindow] flushWindow];
  [panel makeKeyAndOrderFront:nil]; /* was just orderFront: before */
  return self;
}

/*
 * These are packaged as methods so we can easily add accelerator
 * keys that are controlled at the same time...
 */
- (void)enableAdd:(BOOL)flag
{
  [addButton setEnabled:flag];
}

- (void)enableModify:(BOOL)flag
{
  [modifyButton setEnabled:flag];
}

- (void)enableDelete:(BOOL)flag
{
  [controller enableDelete:flag];
  [deleteButton setEnabled:flag]; 
}

/*
 * Control the menu item from here...
 */
- (void)enableUndelete:(BOOL)flag
{
  [controller enableUndelete:flag];
}

- (void)updateButtons
{
  BOOL flag = ([[controller clientList] count] == 0 ? NO : YES);

  [self enableAdd:[currentMgr canAdd]
 	delete:[currentMgr canDelete]
 	modify:[currentMgr canModify]];

  /* Enable these when there are clients */
  [sessionMenuCell setEnabled:flag];
  [expenseMenuCell setEnabled:flag];
}

/*
 * First responder method - pass to view manager
 */
- selectAll:sender
{
  if ( [currentMgr respondsTo:@selector(selectAll:)] )
    return [currentMgr selectAll:sender];

  return nil;			/* is this the right thing to do? */
}
@end
